using Microsoft.SqlServer.Management.Sdk.Sfc;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;

namespace Microsoft.SqlServer.Management.SqlManagerUI.Scripting
{
	internal class FilePerObjectWriterProvider : TextWriterProvider
	{
		private const char InvalidCharacterReplacement = ' ';

		private const string SqlExtension = ".sql";

		private string path;

		private ScriptToFileMode fileMode;

		private Encoding encoding;

		private Dictionary<string, Urn> fileUrnMap = new Dictionary<string, Urn>();

		private Dictionary<Urn, string> urnFileMap = new Dictionary<Urn, string>();

		public FilePerObjectWriterProvider(string path, ScriptToFileMode fileMode, Encoding encoding)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}

            if (path.Length == 0)
            {
                path = "DefaultOutputDirectory";
            }


			if (!Directory.Exists(path))
			{
                try
                {
                    Directory.CreateDirectory(path);
                }
                catch (Exception ex)
                {
                    string msg = string.Format("create directory '{0}' fail", path);
                    throw new Exception(msg, ex);
                }
                //throw new DirectoryNotFoundException(msg);
			}
			this.path = path;
			this.fileMode = fileMode;
			this.encoding = encoding;
		}

		public override TextWriter GetTextWriter(Urn item)
		{
			return this.GetTextWriter(this.GetFileWithPath(this.GetUniqueFileName(item)));
		}

		protected virtual TextWriter GetTextWriter(string fileName)
		{
			return new StreamWriter(fileName, this.ShouldAppend(fileName), this.encoding);
		}

		protected virtual string GetFileWithPath(string fileName)
		{
			return Path.Combine(this.path, fileName + ".sql");
		}

        int _n = 0;
		protected virtual string GetUniqueFileName(Urn urn)
		{
            //return string.Format("filename{0}", _n++);
			string text;
			if (this.urnFileMap.ContainsKey(urn))
			{
				text = this.urnFileMap[urn];
			}
			else
			{
				string validFileName = this.GetValidFileName(urn);
				text = validFileName;
				if (this.IsFileNameTaken(text, urn))
				{
					int num = 1;
					do
					{
						text = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", new object[]
						{
							validFileName,
							num
						});
					}
					while (this.IsFileNameTaken(text, urn));
				}
				this.fileUrnMap.Add(text, urn);
				this.urnFileMap.Add(urn, text);
			}
			return text;
		}

		private bool IsFileNameTaken(string fileName, Urn urn)
		{
			return this.fileUrnMap.ContainsKey(fileName) && urn != this.fileUrnMap[fileName];
		}

		protected virtual string GetValidFileName(Urn urn)
		{
			string fileName = this.GetFileName(urn);
			char[] array = fileName.ToCharArray();
			for (int i = 0; i < array.Length; i++)
			{
				char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
				for (int j = 0; j < invalidFileNameChars.Length; j++)
				{
					char c = invalidFileNameChars[j];
					if (array[i] == c)
					{
						array[i] = ' ';
					}
				}
			}
			return new string(array);
		}

		protected virtual string GetFileName(Urn urn)
		{
			StringBuilder sb = new StringBuilder();
			string attSchema = urn.GetAttribute("Schema");
			if (attSchema != null && attSchema.Length > 0)
			{
				sb.AppendFormat("{0}.", attSchema);
			}

            var attName = urn.GetAttribute("Name");
            if (attName == null)
            {
                attName = GetNoNameUrnName(urn, null);
            }
			sb.AppendFormat("{0}.{1}", attName, urn.Type);
			return sb.ToString();
		}

        private string GetNoNameUrnName(Urn urn, string suffix)
        {
            var parent = urn.Parent;
            if (parent == null)
            {
                return "unknownName" + _n++;
            }
            else
            {
                var attName = parent.GetAttribute("Name");
                if (attName != null)
                {
                    if (!string.IsNullOrEmpty(suffix))
                    {
                        attName += "." + suffix;
                    }
                }

                if (parent.Type == "Table")
                {
                    var attSchema = parent.GetAttribute("Schema");
                    if (attSchema != null && attSchema.Length > 0)
                    {
                        attName = attSchema + "." + attName;
                    }
                    return attName;
                }
                else
                {
                    return GetNoNameUrnName(parent, attName);
                }
            }

        }

		private bool ShouldAppend(string fileName)
		{
            return false;
		}

        
	}
}
